#pragma once
#include <memory>
#include <vector>
#include <string>
#include <cstring>
#include <fstream>
#include "PLF.h"
#include "Segment.h"
#include "misc.h"

struct TGraph {
    unsigned long n, m;
    int mCnt; 
    std::vector<int> id, head, next, adjv; 
    std::vector<PLF> weights;

    TGraph() {
        n = 0;
        m = 0;
        mCnt = 0;
    }

    ~TGraph() {
        head.clear();
        id.clear();
        next.clear();
        adjv.clear();
        weights.clear();
    }

    void init(unsigned long _n, unsigned long _m) {
        this->n = _n;
        this->m = _m;
        head = std::vector<int>(n + 1, -1);
        id = std::vector<int>(n + 1, -1);
        next = std::vector<int>(m, -1);
        adjv = std::vector<int>(m, -1);
        weights = std::vector<PLF>(m);
    }

    void readGraph(const std::string& path) {
        std::ifstream in(path);
        assert(in.is_open());
        unsigned int n, m, interNum, Period;
        in >> n >> m >> interNum >> Period; 
        init(n, m);
        int vs, vt, weight_piece_num;
        int i = 1;
        while (in >> vs >> vt >> weight_piece_num) {
            auto f = std::make_shared<std::vector<Segment>>(weight_piece_num); 
            float t, w;
            for (int i = 0; i < weight_piece_num; i++) {
                in >> t >> w;
                (*f)[i] = { t, w };
            }
            addEdge(vs, vt, f);
        }
        for (int i = 0; i < n; i++)
            id[i] = i;
    }

    void addEdge(int s, int t, std::shared_ptr<std::vector<Segment>>& f) {//https://blog.csdn.net/cry_shoulder/article/details/80144962  
        adjv[mCnt] = t;
        next[mCnt] = head[s];
        head[s] = mCnt;
        weights[mCnt].f = f;
        mCnt++;
    }

    void buildSubgraphs(std::vector<int>& par_cls_idx, TGraph* Gs[], unsigned long cls_num = FANOUT) {
        std::vector<int> count1(cls_num, 0);
        std::vector<int> m(cls_num, 0);
        std::vector<int> new_id(n);
        for (int i = 0; i < n; i++) {
            new_id[i] = count1[par_cls_idx[i]]++;
            for (int j = head[i]; j != -1; j = next[j]) {
                if (par_cls_idx[i] == par_cls_idx[adjv[j]])
                    m[par_cls_idx[i]]++;
            }
        }
        for (int t = 0; t < cls_num; t++) {
            (*Gs[t]).init(count1[t], m[t]);
            for (int i = 0; i < n; i++)
                if (par_cls_idx[i] == t)
                    for (int j = head[i]; j != -1; j = next[j])
                        if (par_cls_idx[i] == par_cls_idx[adjv[j]]) {
                            (*Gs[t]).addEdge(new_id[i], new_id[adjv[j]], weights[j].f);
                        }
        }
        for (int i = 0; i < n; i++)
            (*Gs[par_cls_idx[i]]).id[new_id[i]] = id[i];
    }

};
